1.서론
1.1 팀 소개
회사명: Thinkhole(씽크홀) - 세상을 바꾸는 생각의 통로
팀원: 201832612 김희상, 201932143 임동협, 202032101 강권영, 202031896 조혜진
1.2 프로젝트 기획 배경 및 소개
‘노키즈존(No Kids Zone)’이란 영유아나 어린이의 출입을 금지하는 업소를 가리키는 신조어로, 해외에서는 이미 이러한 규정을 정한 업소가 많이 있는 상태이며 한국에서도 영유아들이 식당, 카페에서 통제불능으로 사고를 당해서 업주가 거액 배상하는 사건 발생하자 지난 2014년부터 국내도 본격적으로 도입하기 시작했다
그러나 맘카페, 뉴스기사 등 여러매체에서 ’노키즈존’이란 안내 표시도 하지 않은 상태로 어린이를 동반한 고객의 출입을 막는 사례를 쉽게 찾아볼 수 있다. 노키즈존을 희망하는 음식점은 늘어나고, 노키즈존에 대한 정보를 알기 희망하는 사람들은 많아지고 있지만 이에 대한 정확한 정보제공이 되지 않는 상태이다.
한국리서치에서 진행한 설문조사에 따르면, 전체 응답자의 11%, 초등학생 이하 자녀가 있는 응답자의 24%가 음식점이나 카페에 도착한 이후에 노키즈존임을 알게 되어 입장을 못하거나 발길을 돌린 경험이 있다고 답했다.
(한국리서치설문조사결과)
이러한 원인은 사업자가 식품위생법 등 현행법상 업소에 노키즈존 운영 여부를 고지해야 할 의무가 없기 때문이다. 사업자 입장에서는 이러한 고지의무가 없기 때문에 노키즈존 여부를 표시할 수 있음에도 불구하고 이를 명확히 표시하는 업체가 적은 것이다. 그리하여 소비자들은 방문 전 노키즈존 여부를 분명 검색했음에도 불구하고 정보가 부족하여 피해를 보는 사례가 많다.
그럼에도 불구하고 아직까지 노키즈존 리스트를 모아서 정보를 제공하는 마땅한 앱이 없는 상황이다. 물론 카카오맵에서는 이미 노키즈존에 대한 분류를 하고 있지만 이는 점주가 직접 자신의 음식점에 노키즈존이라고 표시를 해 놓은 곳만 해당되기 때문에 정보가 터무니없이 부족하여 이용자들이 아직까지 불편함을 호소하고 있다.
그리하여 우리는 노키즈존 업체의 위치 정보를 모아서 제공하는 웹을 구현하기로 기획하였다. 사업자들에게 정확한 정보를 제공받기엔 어려움이 있기 때문에 사업자가 아닌 소비자에게서 정보를 얻기로 계획하였고 그 방법으로 ’SNS크롤링’을 고안했다. 노키즈존에 대한 정보는 검색을 통해 블로그, 카페 등 다양한 곳에서 얻을 수 있으나 그 중 SNS는 많은 사람의 피드백을 얻을 수 있다는 점에서 새로운 데이터에 대한 신뢰성이 다른 웹보다 높다고 판단했다.
노키즈존 위치 정보 제공 앱은 키즈존을 희망하는 사람들과 노키즈존을 희망하는 사람들 모두에게 필요하기 때문에 많은 수요가 예상된다.
문제정의: 사업자 측에서 노키즈존에 대한 위치 정보제공이 원활히 이뤄지고 있지 않아 소비자들이 피해를 보는 사례가 다수 발생
문제해결: SNS를 통해 소비자 측에서 노키즈존에 대한 위치정보를 가져온 후 정리하여 소비자들에게 제공
주요고객: 아이를 키우고 있는 학부모, 노키즈존 가기를 희망하는 사람들
수익창출(사업성): 노키즈존 위치 정보 서비스 앱 개발 후 광고를 통한 수익, 카카오맵과같은 지도사에 데이터 매각, 아이돌봄서비스사 (ex) 째깍언어)와 같은 노키즈존 데이터가 필요한 회사에 데이터 매각
1.3 개발 방향 및 목표
개발 목표: SNS의 노키즈존 음식점 데이터를 크롤링 한 후 기존데이터와 결합하여 노키즈존 지도 웹 개발
개발 방향:
1) 웹 크롤링을 진행하여 노키즈존 음식점 데이터를 가져온다.
2) 공공데이터 포탈에 있는 전국 음식점 데이터를 통해 음식점의 주소를 가져온다.
3) 음식점명과 주소 데이터, xy 좌표를 활용하여 노키즈존 지도 web을 개발한다.
서버 개발: MYSQL
MySQL은 SQL database server이다. 오픈 소스
관계형 데이터베이스 관리 시스템(RDBMS)으로 웹사이트 및 애플리케이션용
데이터를 저장하고 검색하는 데 사용할 수 있다.
mysql서버를 활용하여 데이터를 저장,관리하였다.
1.4 역할분담 및 일정관리
[역할분담]
| 이름 | 역할 |
|---|---|
| 김희상 | 인스타그램 크롤링, 데이터 전처리 및 웹구현 |
| 임동협 | listly를 활용한 카카오맵 크롤링, pandas 데이터 분석 |
| 강권영 | listly를 활용한 yeskidszone 크롤링 |
| 조혜진 | rmarkdown을 활용한 보고서 작성 |
[진행 과정]
| 날짜 | 활동내역 |
|---|---|
| 1주차-4주차 (8/29~9/25) | 팀명 설정 및 아이디어 회의 |
| 5주차 (9/26~10/2) | 피드백 후 주제 수정 |
| 6주차 (10/3~10/9) | 주제선정 및 Github개설, 문제해결을 위한 데이터 수집 방법 모색 |
| 7주차-10주차(10/10~11/6) | 데이터 크롤링 |
| 11주차 (11/7~11/13) | 데이터 전처리 패키지 조사 |
| 12주차 (11/14~11/20) | 데이터 전처리 진행 |
| 13주차 (11/21~11/27) | 데이터 분석 및 Missing Data 처리 - AI 질의응답을 이용한 데이터 분석 |
| 14주차 (11/28~12/04) | 웹구현 진행 및 보고서 작성 |
| 15주차 (12/05~12/11) | 보고서 마무리 및 영상촬영 |
2.본론
2.1 데이터 종류 및 수집방법
사용할 데이터는 다음과 같다.
(1) 인스타그램(SNS)
(2) Yeskidszone
(3) 카카오맵
(4) 공공데이터 포털
2.2.1 인스타그램(SNS)
-데이터 활용 계획
SNS 중 대표적으로 인스타그램을 크롤링할 계획이다. 최근 들어 페이스북, 인스타그램, 트위터와 같은 SNS를 중심으로 노키즈존 정보를 공유하는 사용자가 많아지는 추세인데 그 중 트위터는 광고가 너무 많아 데이터의 질이 좋지 않아 상대적으로 데이터의 질이 좋은 인스타그램에서 데이터를 추출하는 것으로 결정하였다.
인스타그램은 오늘날 가장 많은 사람들이 사용하고 있는 SNS이며 해시태그 기능이 있기 때문에 보다 많은 노키즈존 관련 데이터를 빠르게 얻기 용이하다. 현재 노키즈존 태그는 9.8만개이며 앞으로도 꾸준히 업데이트 될 것이다. 이를 가지고 단어분석을 통해 실제로 노키즈존으로 이용하고 있는 음식점을 분류할 계획이다.
-데이터 수집 방법
데이터 수집 방법은 데이터 종류에 따라 다르다.
인스타그램과 같은 SNS 데이터는 비정형 데이터 이므로 ‘웹크롤링(web crawling)’기법을 사용한다.
‘웹 크롤링’이란 컴퓨터 소프트웨어 기술로 웹 사이트들에서 원하는 정보를 추출하는 것을 의미한다.
웹은 기본적으로 HTML 형태로 되어 있다. 해당 정보가 HTML 형태로 어떻게 보여지는 ‘페이지 소스 보기’ 또는 ‘개발자 검사’ 로 볼 수 있으며 이런 소스들은 보통 개발자들이 어떤 정형화된 형태로 관리하고 있기 때문에 규칙이 생긴다. 이런 규칙을 분석해서 우리가 원하는 정보들만 뽑아오는 것이 웹 크롤링이다.
인스타그램에 노키즈존이라는 키워드를 대입하여 게시글을 크롤링한다. 인스타그램에서 크롤링한 데이터의 변수는 본문, 날짜, 좋아요, 장소, 해시태그이다.
- 사용패키지: Selenium 패키지를 사용
Selenium(셀레늄) 패키지는 웹 사이트에서 데이터를
추출하는 위해 사용되는 Web scraping(웹 정보 수집) 또는 Data Scraping(웹
데이터 추출) 소프트웨어다.
selenium을 활용한 데이터 수집방식은 실제로 우리가
웹브라우저를 통해 검색을 해서 정보를 획득하는 방식과 같기 때문에 코드를
통해 데이터를 수집하기 전에 검색 절차를 살펴봐야 한다.
즉, selenium을 통해서 인스타그램의 데이터를 수집하기
위해서는 사람이 검색 결과를 확인하기 위해 하는 절차를 그대로
따라가야한다.
절차는 다음과 같다.
1. 인스타그램 페이지 접속
2. 검색창에 검색어 입력하고 검색버튼 누르기 (`Selenium`에 선택자를
활용해서 원하는 요소를 선택해준다.)
3. 검색결과 수집하기
[python]
from selenium import webdriver
from bs4 import BeautifulSoup
import time
import re
from selenium.webdriver.common.by import By# 검색결과 페이지의 url을 생성(반환=return)하는 함수 정의
def insta_searching(word):
url = "https://www.instagram.com/explore/tags/" + str(word)
return url
# 검색 결과페이지에서 첫 번째 게시물을 클릭하는 함수 정의
# 함수정의: 열린 페이지에서 첫 번째 게시물 클릭 + sleep 메소드 통하여 시차 두기
def select_first(driver):
first = driver.find_elements(By.CSS_SELECTOR, "div._aagw")[0]
first.click()
time.sleep(3)
# 검색결과 페이지의 url을 생성(반환=return)하는 함수 정의
def insta_searching(word):
url = "https://www.instagram.com/explore/tags/" + str(word)
return url
# 검색 결과페이지에서 첫 번째 게시물을 클릭하는 함수 정의
# 함수정의: 열린 페이지에서 첫 번째 게시물 클릭 + sleep 메소드 통하여 시차 두기
def select_first(driver):
first = driver.find_elements(By.CSS_SELECTOR, "div._aagw")[0]
first.click()
time.sleep(3)
#함수정의: 본문내용, 작성일자, 좋아요 수, 위치정보, 해시태그 가져오기
import re
from bs4 import BeautifulSoup
def get_content(driver):
html = driver.page_source
soup = BeautifulSoup(html, 'lxml')
# 본문 내용
try:
content = soup.select('div._a9zs')[0].text
except:
content = ''
# 해시태그
tags = re.findall(r'#[^\s#,\\]+', content)
# 작성일자
date = soup.select('time._aaqe')[0]['datetime'][:10]
# 좋아요
try:
like = soup.select('div._aacl._aaco._aacw._aacx._aada._aade')[0].findAll('span')[-1].text
except:
like = 0
# 위치
try:
place = soup.select('div._aaqm')[0].text
except:
place = ''
data = [content, date, like, place, tags]
return data
# 함수정의: 첫 번째 게시물 클릭 후 다음 게시물 클릭
def move_next(driver):
right = driver.find_element(By.CSS_SELECTOR, "div._aaqg._aaqh")
time.sleep(3)한 게시물에서 원하는 정보를 긁어온 후 그 다음 게시물로 넘어가는 (게시물의 오른쪽 화살표를 클릭하여 페이징) 함수를 정의한다.
# 크롤링 시작
#driver.get(url)을 통해 검색 페이지 접속하고,
#target 변수에 크롤링할 게시글에 바인딩
# 다운받은 웹 드라이버를 통한 크롬 브라우저 열기
driver = webdriver.Chrome("chromedriver.exe")
driver.get('https://www.instagram.com')
time.sleep(3)
# 인스타그램 로그인을 위한 계정 정보
# email = "__hiksang__siksang__"
# input_id = driver.find_elements(By.CSS_SELECTOR,'input._2hvTZ.pexuQ.zyHYP')[0]
# input_id.clear()
# input_id.send_keys(email)
# password = "thdusdl1!"
# input_pw = driver.find_elements(By.CSS_SELECTOR, 'input._2hvTZ.pexuQ.zyHYP')[1]
# input_pw.clear()
# input_pw.send_keys(password)
# input_pw.submit()
# time.sleep(5)
loginbutton = driver.find_element("xpath", "//*[@id='loginForm']/div/div[3]")
enter_username = driver.find_element("name","username")
password = driver.find_element("name","password")
#CHANGE USERNAME AND PASSWORD WITH YOUR CREDENTIALS.
enter_username.send_keys("kimhiksang")
password.send_keys("rlagmltkd1!")
time.sleep(5)
loginbutton.click()
time.sleep(5)
# 게시물을 조회할 검색 키워드 입력 요청
word = input("검색어를 입력하세요 : ")
word = str(word)
url = insta_searching(word)
검색어를 입력하세요 : 노키즈존본격적으로 머신에게 일을 시키는 코드이다. 코드를 수행하면 인스타그램 메인이 뜨면서 자동으로 로그인이 되고, 검색 키워드를 입력하면 머신이 순차적으로 부분동작을 수행하면서 게시물의 데이터를 크롤링을 한다.
C:\Users\Gachon\AppData\Local\Temp\ipykernel_20588\1733326898.py:46: DeprecationWarning: executable_path has been deprecated, please pass in a Service object
driver = webdriver.Chrome("chromedriver.exe")# 검색 결과 페이지 열기
driver.get(url)
time.sleep(10)
# 첫 번째 게시물 클릭
select_first(driver)
#반복문을 통해 가져올 게시물의 개수와 url정보를 구한다.
# 본격적으로 데이터 수집 시작
results = []
## 수집할 게시물의 수
target = 500
for i in range(target):
try:
data = get_content(driver)
results.append(data)
move_next(driver)
except:
time.sleep(2)
move_next(driver)
time.sleep(5)#결과를 데이터 프레임으로 저장
import pandas as pd
from datetime import datetime
date = datetime.today().strftime('%Y-%m-%d')
results_df = pd.DataFrame(results)
results_df.columns = ['content','date','like','place','tags']
results_df.to_excel(date + '_about '+word+' insta crawling.xlsx'[실행결과] >500개의 인스타그램 ‘노키즈존’ 검색결과
본문과 게시일, 좋아요 수, 장소, 해시태그가 엑셀파일로 저장되었다. 이를
4주간 반복하여 약 10,000개의 데이터를 누적식으로 크롤링하였다.
2.1.2 YESKIDSZONE
-데이터 활용 계획
현재 Yeskidszone이라는 사이트가 운영 중이다. 이 사이트에서는
노키즈존을 사용자에게 제보받아서 운영자가 직접 지도에 노키즈존을
표시해주고 있다.
우리의 프로젝트와 유사하지만 직접 제보를 받아서 지도에 표시해주는
것과 머신러닝을 통해서 추출해낸 데이터로 자동으로 지도에 표시해주는
차이점이 존재한다.
이 사이트에서 등록된 노키즈존의 데이터를 활용하여 우리가 추출해낸 데이터가 얼마나 정확한지 측정할 척도를 만들 예정이다.
-데이터 수집 방법
(수정전)
Listly:(https://www.listly.io/) 사용
(Listly 홈페이지)
Listly는 웹사이트 정보를 엑셀로 변환 시켜 주는 유용한 확장프로그램이다. 어떤 웹사이트에 들어가서 그 사이트의 이미지나 텍스트 등 모든 정보를 엑셀에 저장해서 정렬 또는 데이터를 가공할때 사용할 수 있다.
-사용법
1) 다운로드할 URL 준비
2) 소스 데이터를 추출한 뒤 그룹 생성
3) 모든 추출이 완료될 때까지 대기
4) 엑셀로 다운로드
[실행결과]
Listly 확장프로그램을 사용하여 yeskidszonemap의 음식점명을 크롤링하여 엑셀파일로 저장하였다.
(수정 12/12)
수정이유: Listly로 음식점명만 가져오다보니 중복된 음식점명이 많아 공공데이터에서 adr를 가져올때 신뢰도 문제가 있을 것이라 판단.
따라서 직접 웹크롤링을 하여 adr을 가져오기로 결정하였다.
- 사용패키지: Selenium 패키지를 사용
[Python]
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from bs4 import BeautifulSoup
import time
import re
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import pandas as pd
driver = webdriver.Chrome(ChromeDriverManager().install())
names = []
adrs = []
for i in range(3, 441): # 441
try:
driver.get(
'https://www.google.com/maps/d/viewer?mid=1XNvlhjVsrQFtelWfLapc76MiJ9c&ll=33.5087074%2C126.88813720000009&z=8')
driver.implicitly_wait(10)
right = driver.find_element(By.XPATH,
"//*[@id='legendPanel']/div/div/div[2]/div/div/div[2]/div[1]/div/div[3]/div[441]/span")
right.click() ## 전체보기
driver.implicitly_wait(10)
right = driver.find_element(By.XPATH,
f"//*[@id='legendPanel']/div/div/div[2]/div/div/div[2]/div[1]/div/div[3]/div[{i}]")
right.click() ## 첫번째
# adr = driver.find_element(By.XPATH, "featurecardPanel > div > div > div.qqvbed-bN97Pc > div.qqvbed-VTkLkc.fO2voc-jRmmHf-LJTIlf > div.fO2voc-jRmmHf-MZArnb-Q7Zjwb")
driver.implicitly_wait(10)
name = driver.find_element(By.XPATH, "//*[@id='featurecardPanel']/div/div/div[4]/div[1]/div/div[2]")
# adr = driver.find_element(By.XPATH, "//*[@id='featurecardPanel']/div/div/div[4]/div[2]/div/div[2]")
driver.implicitly_wait(10)
adr = driver.find_element(By.CSS_SELECTOR,
"#featurecardPanel > div > div > div.qqvbed-bN97Pc > div.qqvbed-VTkLkc.fO2voc-jRmmHf-LJTIlf > div.fO2voc-jRmmHf-MZArnb-Q7Zjwb")
names.append(name.text)
adrs.append(adr.text)
print(i)
driver.implicitly_wait(10)
except:
print("not")
df = pd.DataFrame((zip(names, adrs)), columns=['place', 'adr'])
print(df)
df.to_excel("nokids.xlsx")[실행결과]
총 362개의 yeskidszone 음식점명과 주소를 엑셀파일로 저장하였다.
. . . .
.
2.1.3 카카오맵
-데이터 활용 계획
카카오맵은 직접 정보수정 요청을 한 영업장에 한에서 해시태그로 노키즈존을 분류하고 있다. 이 데이터는 정확한 데이터 이므로 카카오맵에 있는 음식점 위치데이터에 인스타그램에서 얻은 데이터를 추가할 계획이다.
-데이터 수집 방법
사용기법: 웹 크롤링
Listly:(https://www.listly.io/) 사용
[실행결과]
총 694개의 카카오맵의 노키즈존 음식점명과 주소, 영업시간 등의 데이터를 크롤링하여 엑셀파일로 저장하였다.
(kakaomap)
2.1.4 공공 데이터 포탈
-데이터 활용 계획
공공데이터 포탈에서는 전국 일반음식점에 대한 데이터가 있다.
음식점이나 카페같은 경우 일반음식점으로 등록되어 있는 경우가 대다수이기
때문에 머신러닝으로 추출한 영업장을 전국 음식점데이터에 대입하여 이에
맞는 주소를 지도에 표시할 예정이다.
-데이터 수집 방법
공공데이터 포탈에서 직접 전국 일반음식점에 대한 데이터를 직접 받는다.
(공공데이터포탈)
2.2데이터 엔지니어링 및 분석
2.2.1 카카오맵,YESKIDSZONE
데이터 처리중에 코로나로 인해서 폐업을 한 영업장이 있을수도 있기 때문에 공공데이터 포탈에서 가져온 전국 음식점 데이터(10월 20일)을 활용하여 폐업한 음식점을 처리했다.
.
전국 음식점 데이터는 위와 같이 영업 기업과 폐업한 기업이 분류되어 있어서 폐업된 곳을 삭제하고 영업중인 곳과 가지고 있는 음식점명 데이터를 비교하여 두 데이터에 동시에 존재하는 데이터만 추출하였다.
과정은 다음과 같다.
1) 공공데이터에서 가져온 전체 음식점 데이터에서 폐업인 데이터 제거
2) 카카오맵, yeskidszone, 전체 음식점 데이터 변수명 변경
3) place와 전체 음식점 데이터 비교
[sql]
.
카카오맵 데이터의 구조는 장소 주소 전화번호 등등으로 이루어져있기 때문에
사용할 변수인 장소, 주소의 이름을 Place와 adr로 변경하였고 예스키즈존의 데이터또한 place로 변경했다.
.
전체 음식점 데이터변수 또한 사업자명을 place, 주소를 adr로 변경하였다.
SELECT * FROM (테이블명) WHERE (속성1) IN (조건1, 조건2, … );
(테이블명)의 테이블에서 (속성1)의 값이 (조건1)이거나 (조건2) 인 행의 모든 열을 선택한다.
크롤링한 데이터의 place의 adr중 전체 음식점명 데이터의 adr과 일치하는 데이터만 가져온다.
[실행결과]
총 836개의 노키즈존 place와 adr을 엑셀파일에 저장하였다.
. . .
.
2.2.2 인스타그램
2.2.2.1 데이터 전처리
인스타그램에서 가져온 Content의 문장들을 ML모델에 넣기 위해서는 최적의 형태로 전처리를 해야 한다. 이미 개발되어 있는 전처리는 영어에 맞춰져 있기 때문에 한국어는 더욱 복잡한 과정이 필요하다. 정형화되지 않은 한국의 문장에는 오타와 신조어 외래어가 포함되어 있어 여러 단계의 전처리 과정이 필요하다. 머신러닝 프로젝트에 사용하기 위해, 데이터를 모델이 이해할 수 있는 형태로 변환하거나 품질을 올리는 일련의 과정을 ‘데이터 전처리’ 라고 한다.
- 불용어 처리
숫자와 필요하지 않은 단어와 이모티콘을 제거하기 위하여 아래의 코드를
사용하여 불용어를 처리해준다.
- 기초적인 전처리
- 크롤링한 데이터일경우 html, tag 제거
- 숫자, 영어 등 필요하지 않은 문자 및 이모티콘 제거
* “@%*=()/+와 같은 punctation 문장 부호 제거
- 문장 분리
한국어에서는 영어와 달리 띄어쓰기가 아닌 문장분리가 존재한다.
문장 분리의 경우에는 형태소 분석으로 종결어미를 구분한다던지, 문장의
CRF(Conditional Random Feild) 결과로 판단하는 방법이 존재한다.
문장분리 부분에서 Kss(Korean Sentence Splitter)라는
패키지는 빠른 속도와 정확성을 보여준다. kss란 카카오에서
사용해오던 문장 분리기에 착안해 C++로 한국어 문장 분리기를 새롭게 만들어
공개한 오픈소스로 nltk의 sent_tokenizer에서 분리하지 못한 마침표 없는
구를 잘 분리해내는 것이 특징이다.
- 정규화
한국어에서 자주 쓰이는 ㅎ ㅎ ㅎ ㅎ ㅎ ㅎ ㅎ, ㅋㅋㅋㅋㅋㅋ등을 정규화하여 기계학습에 적합한 학습자료로 만들어준다
아래는 위의 기법을 적용하여 문장의 불용어처리, 정규화, ML을 활용하여 이해가능한 문맥으로 변환해주는 Python 코드이다.
[python]
import pandas as pd
import emoji
from emoji import core
import re
import kss
import openpyxl
data = pd.read_excel('Data.xlsx')
content = data['content']
## 불용어 처리를 위한 코드
punct = "/-'?!.,#$%\'()*+-/:;<=>@[\\]^_`{|}~" + '""“”’' + '∞θ÷α•à−β∅³π‘₹´°£€\×™√²—–&'
punct_mapping = {"‘": "'", "₹": "e", "´": "'", "°": "", "€": "e", "™": "tm", "√": " sqrt ", "×": "x", "²": "2",
"—": "-", "–": "-", "’": "'", "_": "-", "`": "'", '“': '"', '”': '"', '“': '"', "£": "e",
'∞': 'infinity', 'θ': 'theta', '÷': '/', 'α': 'alpha', '•': '.', 'à': 'a', '−': '-', 'β': 'beta',
'∅': '', '³': '3', 'π': 'pi', }
def clean_punc(text, punct, mapping):
for p in mapping:
text = text.replace(p, mapping[p])
for p in punct:
text = text.replace(p, f' {p} ')
specials = {'\u200b': ' ', '…': ' ... ', '\ufeff': '', 'करना': '', 'है': ''}
for s in specials:
text = text.replace(s, specials[s])
return text.strip()
def clean_text(texts):
corpus = []
for i in range(0, len(texts)):
review = re.sub(r'[@%\\*=()/~#&\+á?\xc3\xa1\-\|\.\:\;\!\-\,\_\~\$\'\"]', '',
str(texts[i])) # remove punctuation
review = re.sub(r'\d+', '', str(texts[i])) # remove number
review = review.lower() # lower case
review = re.sub(r'\s+', ' ', review) # remove extra space
review = re.sub(r'<[^>]+>', '', review) # remove Html tags
review = re.sub(r'\s+', ' ', review) # remove spaces
review = re.sub(r"^\s+", '', review) # remove space from start
review = re.sub(r'\s+$', '', review) # remove space from the end
corpus.append(review)
return corpus
def clean_str(text):
pattern = '([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)' # E-mail제거
text = re.sub(pattern=pattern, repl='', string=text)
pattern = '(http|ftp|https)://(?:[-\w.]|(?:%[\da-fA-F]{2}))+' # URL제거
text = re.sub(pattern=pattern, repl='', string=text)
pattern = '([ㄱ-ㅎㅏ-ㅣ]+)' # 한글 자음, 모음 제거
text = re.sub(pattern=pattern, repl='', string=text)
pattern = '<[^>]*>' # HTML 태그 제거
text = re.sub(pattern=pattern, repl='', string=text)
pattern = '[^\w\s\n]' # 특수기호제거
text = re.sub(pattern=pattern, repl='', string=text)
text = re.sub('[-=+,#/\?:^$.@*\"※~&%ㆍ!』\\‘|\(\)\[\]\<\>`\'…》]','', string=text)
text = re.sub('\n', '.', string=text)
return text
## 문장 정규화를 위한 코드
# from soynlp.normalizer import *
# print(repeat_normalize("안녕하세요 ㅎㅎㅎㅎㅎㅎㅎㅎㅎㅎㅎ 아 진자 배고파 ㅎㅋㅋㅋㅋㅋㅋ", num_repeats=2))
## 문장의 불용어와 정규화를 진행
## kss 패키지를 사용하여 자연스러운 문맥단위의 띄어쓰기가 사용된 문장으로 변
db = pd.DataFrame(columns=["content", "data", "place"])
for i in range(len(data)):
try:
bb = data['date'][i]
cc = data['place'][i]
a = clean_punc(data['content'][i], punct, punct_mapping)
b = clean_str(a)
aa = " ".join(kss.split_sentences(b))
db = db.append({'content': aa,
"data": bb,
'place': cc}, ignore_index=True)
except:
print("empty")
print(db)
db3 = db.drop_duplicates()
db3.to_excel("preprocess1.xlsx")한국어 전처리를 완료한 데이터를 SQL에 저장하였다.
지도 웹을 구현하기 위해서는 장소와 노키즈존이라는 키워드를 담는 본문만 필요하다고 판단되어 Place, content 부분만 추출하여 저장하였다.(해시태그는 본문에 포함되어 있어 삭제해도 무방하다고 판단)
[실행결과]
실행결과 중복된 데이터가 존재하여
중복된 자료를 제거해주는 SQL 쿼리문을 사용하였다.
[sql]
.
(중복데이터삭제후)
중복된 데이터를 삭제하여 전처리를 완료하였다.
2.2.2.2 데이터 분석
1) ‘노키즈존’ place 추출
-사용패키지 : Pandas(판다스) 사용
Pandas는 데이터를 분석 및 조작하기 위한 파이썬 언어
소프트웨어 라이브러리로, 쉽고 직관적인 관계형 또는 분류된 데이터로
작업할 수 있도록 설계되었다. 행과 열로 이루어진 데이터 객체를 만들어
다룰 수 있게 되며 보다 안정적으로 대용량의 데이터들을 빠르고 유연하게
처리할 수 있어 매우 편리한 도구이다. Excel 스프레드 시트와 같은
이질적으로 유형이 지정된 열이 있는 테이블 형식의 데이터에 적합한 분석
패키지이다.
pandas에는 Series와 DataFrame이라는 두 종류의 자료구조가
있다. pandas의 Series는 1차원 배열과 같은 자료구조이고
dataframe은 2차원 레이블이다. 데이터베이스관점에서 열(Column)이 하나만
있으면 시리즈이다.
Pandas는 부동 소수점 데이터뿐만 아니라 누락된
데이터(NaN)를 손쉽게 처리하며 데이터를 집계 및 변환하기 위해 데이터
세트에 분할 적용 및 유연한 그룹 별 기능이 가능하다. 또한 다른 Python 및
NumPy 데이터 구조의 비정형 색인 생성 데이터를 DataFrame 객체로 쉽게
변환할 수 있다.
이를 활용하여 인스타그램에서 수집 후 전처리한 데이터 중 content에 ‘노키즈존’ 키워드를 담고있는 place데이터를 분석한다.
[python]
#엑셀파일 Series(시리즈)로 가져오기
import pandas as pd
nk = []
j = 1
l = 0
df = pd.read_excel('1_pre.xlsx', usecols = ['content']) #사용할 열 지정
sf = pd.read_excel('1_pre.xlsx', usecols = ['place'])
#print(df['content'][l]) #파일명['열이름']['행이름']
#print(sf['place'][l])
k=df['content'][0].split()
#print(k[1])
nokids = 'false'
for l in range(len(df)) :
for i in range(len(k)) :
if k[i] == '노키즈존' :
nokids = 'true'
i = i+1
elif k[i] == '노키즈' :
nokids = 'true'
i = i+1
elif k[i] == 'nokid':
nokids = 'true'
i = i+1
elif k[i] == 'nokids':
nokids = 'true'
i = i+1
elif k[i] == 'Nokid':
nokids = 'true'
elif k[i] == 'Nokid':
nokids = 'true'
elif k[i] == '예스키즈존':
nokids = 'false'
i = i+1
elif k[i] == '예스키즈':
nokids = 'false'
elif k[i] == 'yeskids':
nokids = 'false'
elif k[i] == 'Yeskids':
nokids = 'false'
i = i+1
else :
i = i+1
if nokids == 'true' :
if sf['place'][l] != '' :
nk.append(sf['place'][l])
l = l+1
else :
l = l+1
n=0
for m in range(len(df)):
nk[m] = str(nk[m])
if nk[m] != 'nan' :
nk[n] = nk[m]
n = n+1
m = m+1
nk = set(nk)
nk = list(nk)
nn = pd.DataFrame(nk)
print(nn)
nn.to_excel("nokids.xlsx")[실행결과]
Pandas패키지를 활용하여 인스타 크롤링 엑셀 자료를 불러와
1차원 데이터(시리즈)로 변형 후 노키즈존, 노키즈, nokids, nokid, Nokids,
Nokid로 명시되어있는 place들을 추출하였다. Place에서
결측값을 제거한 데이터들은 DataFrame으로 변형하여 Excel로 저장하였다.
.
2) api 기계독해를 통한 place 분석-missing data 처리
URL:https://aiopen.etri.re.kr/demo/MRCServlet
기계독해(Machine Reading Comprehension)란 정답을 포함하는 단락과 자연어 질문을 입력 받아 정답의 영역을 찾는 기술을 말한다.
.
예시
.
기계 독해는 문장을 제시하고 이에 대한 질문을 하면 기계가 이미 처리된 데이터들을 활용하여 질문에 대한 대답을 하는 것으로 이에 대한 결과값으로 정답과 이에 대한 confidence(신뢰도)를 제공한다.
.
한국 전자통신연구원에서 공개하고 있는 언어처리 api중 기계독해 부분을 활용하여 place가 NULL값인 content를 분석했다.
이 api에게 “노키즈존인 곳이 어디야?”라는 질문을 통해 cotent에서 노키즈존인 place를 추출했다.
[python]
import urllib3
import json
import pandas as pd
# 공공 인공지능 OPEN API 사용
openApiURL = "http://aiopen.etri.re.kr:8000/MRCServlet"
accessKey = "f6387a7b-9790-4866-84f5-a7b4c7b63e8c"
question = "노키즈존인 곳이 어디야?"
# 전처리된 파일을 Load
data = pd.read_excel('1_pre.xlsx')
content = data['content']
test = content[3]
db = pd.DataFrame(columns=["place", "confidence"])
# AI를 활용한 언어처리
for i in range(len(data)):
try:
passage = data['content'][i]
requestJson = {"argument": {"question": question, "passage": passage}}
http = urllib3.PoolManager()
response = http.request("POST", openApiURL, headers={"Content-Type": "application/json; charset=UTF-8","Authorization": accessKey}, body=json.dumps(requestJson))
a = json.loads(response.data.decode('utf-8'))['return_object']['MRCInfo']['answer']
b = json.loads(response.data.decode('utf-8'))['return_object']['MRCInfo']['confidence']
db = db.append({'place': a,
"confidence": b,
}, ignore_index = True)
print(a,b)
except:
print("Missing Data")
db3 = db.drop_duplicates()
# mlplace.xlsx 파일 생성
db3.to_excel("mlplace.xlsx")[실행결과]
.
content에서 약 3200개의 place가 confidence와 함께 저장되었다.
이 중 confidence가 0.9이상인 데이터를 추출하여 사용했다.
[sql]
.
AI로 추출한 place를 인스타그램에서 추출한 기존 place와 결합 후 전국 음식점 데이터와 비교하여 실제 존재하는 음식점이면 사용하고 아니면 걸러내는 필터를 만들어서 한번 더 데이터를 가공했다.
[sql]
.
[실행결과]
.
결합한 데이터와 전국음식점 데이터를 비교한 후 약 1200개의 최종적인 place, adr데이터를 가져왔다.
2.2.3 부족한 변수 생성
지도웹을 구현하기 위해서는 음식점명, 주소, 좌표 데이터가 필요하다. 그러나 현재 음식점명, 주소 데이터밖에 없으므로 주소를 x,y 좌표로 변경하여 좌표 데이터를 생성한다.
도로명주소를 좌표로 치환하는 Python 코드를 네이버 api를 활용하여 만들어 사용하였다.
이 과정에서 좌표로 나타나지 않은 missing data는 삭제하였다.
최종 데이터를 얻기 전, 카카오맵과 Yeskidszone 결합데이터를 지도로 먼저 구현해보기 위해 좌표 데이터를 생성했다.
[python]
from korean_geocoding.geocoding import KoreanGeocoding as Kg
import openpyxl
import time
## NAVER API를 활용하여 주소를 위도 경도로 변환
kg = Kg()
kg.set_naver_api("hdfa8f31bk", "3uD3bopOrcTwYjeC6TnLOQxGDqIkwNPPYlhYo4JI")
## place와 주소로 이루어진 last.xlxs load
filename = "kakao_yes_adr.xlsx"
exelFile = openpyxl.load_workbook(filename)
## 주소를 위도와 경도로 변경해주는 코드
sheet = exelFile.worksheets[0]
rowCount = 1
for row in sheet.rows:
try:
print(row[1].value)
g = kg.get_coordinates_by_api(row[1].value)
lat_cell = sheet.cell(row=rowCount, column=3)
lng_cell = sheet.cell(row=rowCount, column=4)
lat_cell.value = g[0]
lng_cell.value = g[1]
rowCount = rowCount + 1
except:
rowCount = rowCount + 1
print("error")
## kakao_yes_latlng.xlsx로 저장
exelFile.save("kakao_yes_latlng.xlsx")[실행결과]
. . .
.
이후 같은 코드를 이용하여 인스타그램 데이터까지 결합한 최종 데이터의 좌표 데이터를 생성하였다.
from korean_geocoding.geocoding import KoreanGeocoding as Kg
import openpyxl
import time
## NAVER API를 활용하여 주소를 위도 경도로 변환
kg = Kg()
kg.set_naver_api("hdfa8f31bk", "3uD3bopOrcTwYjeC6TnLOQxGDqIkwNPPYlhYo4JI")
## place와 주소로 이루어진 last.xlxs load
filename = "last.xlsx"
exelFile = openpyxl.load_workbook(filename)
## 주소를 위도와 경도로 변경해주는 코드
sheet = exelFile.worksheets[0]
rowCount = 1
for row in sheet.rows:
try:
print(row[1].value)
g = kg.get_coordinates_by_api(row[1].value)
lat_cell = sheet.cell(row=rowCount, column=3)
lng_cell = sheet.cell(row=rowCount, column=4)
lat_cell.value = g[0]
lng_cell.value = g[1]
rowCount = rowCount + 1
except:
rowCount = rowCount + 1
print("error")
## nokids.xlsx로 저장
exelFile.save("nokids.xlsx")[실행결과]
.
2.3 Web 구현
2.3.1 카카오맵+yeskidszone web 구현
kakao_yes_latlng.xlsx를 카카오맵 API에 필요한 형식으로 변환해준 후
js를 이용하여 web구현을 하였다.
2.3.2 최종 데이터 web 구현
같은 방법으로 nokids.xlsx를 카카오맵 API에 필요한 형식으로 변환해준
후 js를 이용하여 web구현을 하였다.
[python]
import openpyxl
import time
import sys
import pandas as pd
## 카카오 지도 API를 활용하기 위한 딕셔너리 형식을 만드는 코드
## 엑셀파일 열기
filename = "nokids.xlsx"
exelFile = openpyxl.load_workbook(filename)
## 시트 설정
sheet = exelFile.worksheets[0]
df = pd.DataFrame()
adr = []
rowCount = 1
for row in sheet.rows:
try:
a = row[0].value
b = row[2].value
c = row[3].value
print(row[0].value)
print(row[1].value)
print(row[2].value)
k = dict()
k['title'] = a
k['lat'] = b
k['lng'] = c
adr.append(k)
except:
print("error")
## 식당명, X, Y 로 구성된 데이터를 웹을 구현하는데 필요한 형식인
## {'title': '식당명', 'lat': 37.5654272, 'lng': 126.9816208} 으로 변경
new_adr = [i for i in adr if i['lat'] != None]
f = open('kakao_map_input.txt', 'w')
print(new_adr, file=f)
f.close()[실행결과]
.
[js]
[실행결과]
.
마커에 커서를 가져다 놓으면 음식점명이 보인다.
2.3.3 기존 노키즈존 지도와 비교
카카오맵과 yeskidszone 데이터를 합쳐 기존보다 더 많은
노키즈존 정보가 있는 지도 웹을 만들었다.
.
여기에 인스타크롤링을 통해 새롭게 얻은 노키즈존 데이터를 추가하였다.
3. 결론
3.1 기대효과 및 보완점
-기대효과
이 노키즈존 웹은 현재 사용한 데이터 뿐만 아니라 블로그, 카페등 다양한 곳에서 웹크롤링을 통해 데이터를 가져와 추가할 수 있기 때문에 웹의 성장가능성은 높은 편으로 예상된다.
또한 한국리서치에서 진행한 조사에 따르면 전체 응답자의 84%가
웹사이트나 지도 어플리케이션에 매장 정보를 제공할 때 노키즈존인지 여부도
필수적으로 제공해야 한다고 답했다. 노키즈존 업장을 선택하려는 소비자의
수요가 있고, 영유아나 어린이를 동반했을 때 헛걸음을 하지 않기 위해서라도
필요한 정보라는 의견이 다수를 차지한 것이다. 성별이나 연령대, 초등학생
자녀 유무 등과 관계없이 모두 노키즈존 여부도 필수적으로 제공해야 한다는
의견이 다수를 차지하였다.
(한국리서치)
이러한 설문조사에 따르면 노키즈존 매장 정보 데이터의 수요는 많을 것으로 예상된다.
따라서 노키즈존 정보 제공 웹은 아이들과 함께하는 외출에 헛걸음하는 것을 막을 뿐만 아니라 노키즈존을 찾는 소비자들에게 편리함을 제공할 것으로 기대된다.
반면 노키즈존이 확산됨에 따라 업주들 사이에는 예스키즈존 마케팅이 떠오르고 있다. 외식 서비스가 진화하면서 최근에는 어린아이의 입장에 제한을 두거나, 정반대로 키즈 서비스 강화를 통해 가족 고객들의 충성도를 높이는 추세로 양분화 되고 있는 것이다. 이는 어느 고객을 타겟으로 하냐에 따라 다르다.
결국 노키즈존과 예스키즈존에 기반을 둔 마케팅은 둘 다 일부 고객을 상실할 수 있는 리스크를 가지고 있는 동시에 확실한 타겟팅을 통해 충성 고객을 확보하는 하나의 마케팅 전략으로 활용되고 있다. 이는 키즈존의 여부가 음식점의 매출에 영향을 미친다는 것을 의미한다.
이러한 점을 볼 때 이 웹은 음식점의 매출에도 영향을 줄 것으로 예상되어 소비자뿐만 아니라 업주들도 관심을 가질 것으로 기대된다.
-보완점
인스타그램에서 place값을 더 많이 가져오기 위해 AI API를 사용했는데, 이 AI 기계독해로부터 얻은 데이터가 신뢰할만한지 증명할 수 없다. 신뢰도가 0.9이상인 데이터를 가져오긴 했지만, 프로그램 자체의 신뢰성에 대해선 알 수 없다.
3.2 READ ME
(1) 프로젝트명 및 기능
가천대학교 조사방법론2 프로젝트 개시
주제: 노키즈존 지도 웹 개발
기능: 노키즈존 음식점 위치 정보 제공
(2)개발환경(s/w)
| 구 분 | 항 목 | 적용내역 |
|---|---|---|
| OS | Windows 10 | 통합 개발 환경 실행 |
| macOS 10 | 통합 개발 환경 실행 | |
| 개발환경(IDE) | pycharm CE | Python 프로젝트 단위로 빌드를 실행 |
| Jupyter notebook | Python 셀 단위 개별 컴포넌트 실험용 | |
| datagrip | DB SQL 관리 | |
| Visual Studio Code | java를 사용하여 web구현 | |
| 개발도구 | Webdriver |
selenium 라이브러리 |
BeautifulSoup |
HTML 핸들링 라이브러리 | |
pandas |
python 데이터 핸들링 라이브러리 | |
Datetime |
sython 내장모듈로 날짜와 시간 처리 | |
Emoji, Core, Kss |
한국어 전처리를 위한 라이브러리 | |
Openpyxl |
파이썬에서 엑셀을 핸들링 하기위한 라이브러리 | |
Urlib3 |
api를 활용하기 위한 라이브러리 | |
json |
python에서 json 형식을 다루기 위한 라이브러리 | |
KoreanGeocoding |
네이버 API를 활용하기 위한 라이브러리 | |
Sys |
python 인터프리터를 활용하기 위한 라이브러리 | |
| 개발언어 | python | 데이터 엔지니어링 및 분석 |
| sql | 데이터 엔지니어링 | |
| js | Web구현 |
(3) github code 설명
PYTHON
| 파일명 | 설명 |
|---|---|
| insta_crawling.ipynb | 인스타 크롤링(mac) |
| insta_crawling_window.ipynb | 인스타 크롤링(win) |
| crawling_yeskids.py | yeskidszone 크롤링 |
| naver_blog_cafe_craw.ipynb | 네이버 블로그 카페 크롤링 |
| AI_nokids.py | AI를 활용하여 노키즈존을 분류하는 프로그램 |
| latlng.py | 주소가 있는 엑셀파일을 위도와 경도로 변경해주는 프로그램 |
| preprocess.py | 문장의 불용어처리, 정규화, ML을 활용하여 이해가능한 문맥으로 변환해주는 프로그램 |
| to_kakaomap_input.py | 카카오맵 API에 필요한 형식으로 변환해주는 프로그램 |
| twetter_crawling.py | 트위터 크롤링 |
| twitter_crawling.R | 트위터 크롤링(R) |
SQL
| 파일명 | 설명 |
|---|---|
| DE.sql | DE를 위한 쿼리문 |
(4)DATA 설명
| 파일명 | 설명 |
|---|---|
| crawling_blog.csv | 블로그 크롤링 |
| crawling_cafe.csv | 카페 크롤링 |
| Craw_insta_all.xlsx | 인스타그램 크롤링 데이터 |
| yeskids.csv | yeskidszone data(리스틀리) |
| kakaomap.csv | 카카오맵 노키즈존 데이터(리스틀리) |
| kakao_yes_adr.xlsx | 수정된 yeskidszone과 kakaomap 결합데이터 |
| preprocess.csv(xlxs) | 인스타그램 데이터 전처리 데이터 (중복제거 X) |
| preprocess1.csv(xlxs) | 인스타그램 데이터 전처리 데이터 (중복제거 O) |
| nokids_outlier.xlsx | 인스타그램 노키즈존 pandas 활용 추출 |
| mlplace.csv(xlxs) | AI 활용 노키즈존 추출 데이터 with confidence |
| last.xlsx | 최종 음식점이름(place)과 주소가 있는 데이터 |
| nokids_latlng.xlsx | 최종 음식점이름과 주소 위도 경도가 있는 데이터 |
| kakao_map_input.txt | 카카오맵 api에 필요한 데이터형식으로 변환한 데이터 |
| rmarkdown | 프로젝트 보고서 rmd 및 html |
3.4 참고문헌
김세은, 『“노키즈존인지 알려라도주세요”』,스냅타임,https://m.edaily.co.kr/news/Read?newsId=01128326629083032,2021.06.18
꾸러기면이,한글 text sentence split 비교(nltk, kss) in python,https://blog.naver.com/statp_r/222685273409
bykitty,판다스(Pandas)란? - 이론, 기초 (tistory.com), https://1000yun.tistory.com/2
문범우,pandas(판다스) 기초 정리.https://doorbw.tistory.com/172
jochedda,[NLP] 한국어 자연어 전처리 (velog.io), (https://velog.io/@jochedda/NLP-%EC%9E%90%EC%97%B0%EC%96%B4-%EC%A0%84%EC%B2%98%EB%A6%AC)
정용범 외, 사장님 몰래 하는 파이썬 업무자동화,https://wikidocs.net/137914
byeoljubu,python Selenium 패키지를 사용 홈페이지 정보 취득하기,https://www.zinnunkebi.com/python-selenium-web-scraping/
지표덕후,[파이썬Python] 인스타그램 해쉬태그(#) 검색결과 크롤링하기,https://mokeya.tistory.com/68
구기모, 웹페이지 정보를 엑셀(스프레드시트)로 정리하기(feat. 웹 크롤링),(https://m.blog.naver.com/richrule/222638742287)
이동한,『[기획] 노키즈존에 대한 여론은?』,한국리서치 여론속의여론https://hrcopinion.co.kr/archives/20056#,2021.12.01
소상공인창업전략연구소 대표,[조계범 대표의 창업이야기] 노키즈 vs 예스키즈 마케팅,영남일보,https://www.yeongnam.com/web/view.php?key=20180407.010120826220001,2018.04.07
Yihui Xie, J. J. Allaire, Garrett Grolemund (2022),R Markdown: The Definitive Guide,https://bookdown.org/yihui/rmarkdown/
이용희, Rstudio 에서 R markdown 화일로 HTML 리포트 작성하기, https://ilovedata.github.io/teaching/creative01/myreport.html
s_ih_yun,[Github] README란? README.md 작성법,https://codesyun.tistory.com/284